package com.liu.cloud.rule;

import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.Server;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.math.RandomUtils;
import org.springframework.util.CollectionUtils;

import java.util.List;

/**
 * hash负载均衡规则
 *
 * @author LIU
 * @version 1.0.0
 */
@Slf4j
public class HashLoadBalanceRule extends AbstractLoadBalancerRule {


    private static final String DEFAULT_KEY = "default";

    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {

    }

    @Override
    public Server choose(Object key) {
        List<Server> servers = this.getLoadBalancer().getReachableServers();

        if (CollectionUtils.isEmpty(servers)) {
            return null;
        }
        // 只有一个服务，则默认选择
        if (servers.size() == 1) {
            return servers.get(0);
        }
        // 多个服务时，当key不存在时，随机选择
        if (key == null || DEFAULT_KEY.equals(key)) {
            return randomChoose(servers);
        }
        // 多个服务时，key存在，根据key hash
        return hashKeyChoose(servers, key);
    }

    /**
     * 随机选择一个服务
     *
     * @param servers 可用的服务列表
     * @return 随机选择一个服务
     */
    private Server randomChoose(List<Server> servers) {
        int randomIndex = RandomUtils.nextInt(servers.size());
        return servers.get(randomIndex);
    }

    /**
     * 根据key hash选择一个服务
     *
     * @param servers 可用的服务列表
     * @param key     自定义key
     * @return 根据key hash选择一个服务
     */
    private Server hashKeyChoose(List<Server> servers, Object key) {
        int hashCode = Math.abs(key.hashCode());
        if (hashCode < servers.size()) {
            return servers.get(hashCode);
        }
        int index = hashCode % servers.size();
        log.info("wellId:{},choose:{},available services:{}",key,servers.get(index),servers);
        return servers.get(index);
    }

}
